﻿using Nemerle2.Compiler;
using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

using NUnit.Framework;
using TestAssembly;

namespace Test
{
  /// <summary>
  /// Description of AttributeTests.
  /// </summary>
  [TestFixture]
  public class AttributeTests : AssemblyTests
  {
    [Test]
    public Test():void
    {
      def attrs = CommonProject.LoadedAssemblies.First(a => a.Name == "TestAssembly").CustomAttributes.CustomAttributes;
      def attr  = attrs.First(attr => attr.FullName == typeof(MyAttr).FullName.Replace('+','.'));

      Assert.AreEqual(1, attr.PositionalArgumentCount, "Invalid PositionalArgumentCount");
      Assert.AreEqual(10, attr.PositionalArguments.Head.ToObject());
      Assert.AreEqual(5, attr.NamedArguments.Length, "Invalid NamedArgumentCount");
      Assert.AreEqual("str", attr.NamedArgumentValue["NamedStrArg"].ToObject());
      
      def testTypeValue(attrValue, name)
      {
        match (attrValue)
        {
          | CustomAttributeValue.Type(val) => Assert.AreEqual(val.ToString(), name);
          | _ => Assert.Fail("Expected CustomAttributeValue.Type()");
        }
      }
      
      // VladD2: TODO: Если в атрибуте задан тип как "List[_]", то в FixedType представляющем его
      // он должен описываться как TypeParameterInfoRef(x), где x - это описание параметра типов в формате ITypeParameterInfo.
      //testTypeValue(attr.NamedArgumentValue["NamedType1Arg"], "List[T]");
      testTypeValue(attr.NamedArgumentValue["NamedType2Arg"], "List[Int32]");
      testTypeValue(attr.NamedArgumentValue["NamedType3Arg"], "String");
      
      def arrArg = attr.NamedArgumentValue["NamedArrArg"].ToObject() :> Seq[object];
      Assert.IsTrue(array[1, 2, 4].SequenceEqual(arrArg.Cast.[int]().ToArray()), "Error in array args attributes ");
      Assert.AreEqual(typeof(MyAttr).FullName.Replace('+', '.'), attr.Type.FullName, "Invalid type full name");
      
      // Attributes from C# assembly...
      
      def ty = CommonProject.LoadedAssemblies.First(a => a.Name == "CSharpTestAssembly").AllTypes
                  .First(t => t.Name == "Class1");
      
      // A attribute with argument of enum type on class...
      
      Assert.AreEqual(["CSharpTestAssembly.TestAttr"], ty.CustomAttributes.CustomAttributeNames);
      def attr2 = ty.CustomAttributes.CustomAttributes.Head;
      Assert.AreEqual(1, attr2.PositionalArgumentCount);
      def attrValue2 = attr2.PositionalArguments.Head;
      Assert.IsTrue(attrValue2 is CustomAttributeValue.Enum);
      Assert.AreEqual("TestEnum.Value1", attrValue2.ToString());
    }
  }
}
